﻿using AutoMapper;
using IOA.MES.Common;
using IOA.MES.DataAccess.Entity;
using IOA.MES.DataAccess.Enum;
using IOA.MES.DataAccess.VModel;
using System;
using System.Collections.Generic;
using System.Linq;

namespace IOA.MES.Business
{
    /// <summary>
    /// 线边物料管理(错误代码：142000)
    /// </summary>
    public class LineMaterialMgr
    {
        private MESContext mesDb = new MESContext("MES");

        /// <summary>
        /// 保存物料单据
        /// </summary>
        public void SaveLineMaterialBill(VLineMaterialBill model)
        {
            var workOrder = mesDb.WorkOrders.AsNoTracking().FirstOrDefault(_ => _.WorkOrderNo == model.WorkOrderNo && _.Valid);
            model.WorkshopCode = workOrder.WorkshopCode;
            model.WorkshopName = workOrder.WorkshopName;
            model.OrderNo = workOrder.OrderNo;

            var line = mesDb.AssemblyLines.AsNoTracking().FirstOrDefault(_ => _.PkId == model.LineId && _.Valid);
            model.LineName = line.LineName;

            model.CreateTime = DateTime.Now;
            var entity = Mapper.Map<LineMaterialBill>(model);

            var allocateProductIds = model.Items.Select(_ => _.PkId).Distinct().ToList();
            var allocateProducts = mesDb.AllocateProducts.AsNoTracking().Where(_ => _.Valid && allocateProductIds.Contains(_.PkId)).ToList();
            var items = new List<LineMaterialBillItem>();
            foreach (var item in model.Items)
            {
                var allocateProduct = allocateProducts.FirstOrDefault(_ => _.PkId == item.PkId);
                if (allocateProduct == null)
                {
                    continue;
                }
                items.Add(new LineMaterialBillItem
                {
                    BillType = entity.BillType,
                    AllocateNo = allocateProduct.AllocateNo,
                    AllocateProductId = allocateProduct.PkId,
                    CategoryCode = allocateProduct.CategoryCode,
                    CategoryName = allocateProduct.CategoryName,
                    ProductCode = allocateProduct.ProductCode,
                    ProductName = allocateProduct.ProductName,
                    ProductSpecs = allocateProduct.Specifications,
                    ProductCompany = allocateProduct.ProductionCompany,
                    BatchNo = allocateProduct.BatchNo,
                    BatchNoBig = allocateProduct.BatchNoBig,
                    BatchNoSmall = allocateProduct.BatchNoSmall,
                    Quantity = item.Quantity,
                    CreateBy = model.CreateBy,
                    CreateTime = DateTime.Now
                });
            }

            //发料单
            if (model.BillType == LineMaterialBillType.Issue)
            {
                mesDb.LineMaterialBills.Add(entity);
                mesDb.SaveChanges();
                entity.BillNo = DateTime.Today.ToString("yyyyMMdd") + (entity.PkId % 100000).ToString("00000");
                items.ForEach(_ =>
                {
                    _.BillNo = entity.BillNo;
                });
                mesDb.LineMaterialBillItems.AddRange(items);

                var storages = items.Select(_ => new LineStorage
                {
                    BillNo = entity.BillNo,
                    WorkshopCode = entity.WorkshopCode,
                    WorkshopName = entity.WorkshopName,
                    OrderNo = entity.OrderNo,
                    WorkOrderNo = entity.WorkOrderNo,
                    AllocateNo = _.AllocateNo,
                    AllocateProductId = _.AllocateProductId,
                    CategoryCode = _.CategoryCode,
                    CategoryName = _.CategoryName,
                    ProductCode = _.ProductCode,
                    ProductName = _.ProductName,
                    ProductSpecs = _.ProductSpecs,
                    ProductCompany = _.ProductCompany,
                    BatchNo = _.BatchNo,
                    BatchNoBig = _.BatchNoBig,
                    BatchNoSmall = _.BatchNoSmall,
                    LineId = entity.LineId,
                    LineName = entity.LineName,
                    OriginQuantity = _.Quantity,
                    Quantity = _.Quantity,
                    CreateBy = model.CreateBy,
                    CreateTime = DateTime.Now
                }).ToList();
                mesDb.LineStorages.AddRange(storages);
                mesDb.SaveChanges();
            }
            else //退料单
            {
                var exBatchNoSmalls = new List<string>();
                foreach (var item in items)
                {
                    var storages = mesDb.LineStorages.AsNoTracking().Where(_ => _.LineId == entity.LineId && _.WorkOrderNo == entity.WorkOrderNo && _.AllocateProductId == item.AllocateProductId && _.Quantity > 0 && _.Valid)
                        .OrderByDescending(_ => _.PkId).ToList();
                    if (storages.Sum(_ => _.Quantity) < item.Quantity)
                    {
                        exBatchNoSmalls.Add(item.BatchNoSmall);
                        continue;
                    }

                    var remainQuatity = item.Quantity;
                    foreach (var storage in storages)
                    {
                        mesDb.LineStorages.Attach(storage);
                        if (storage.Quantity > remainQuatity)
                        {
                            storage.Quantity = storage.Quantity - remainQuatity;
                            storage.ModifyBy = entity.CreateBy;
                            storage.ModifyTime = DateTime.Now;
                            remainQuatity = 0;
                        }
                        else
                        {
                            remainQuatity = remainQuatity - storage.Quantity;
                            storage.Quantity = 0;
                            storage.ModifyBy = entity.CreateBy;
                            storage.ModifyTime = DateTime.Now;
                        }
                        if (remainQuatity <= 0)
                        {
                            break;
                        }
                    }
                }

                if (exBatchNoSmalls.Any())
                {
                    throw new MultiLanBizException(142001, string.Join("、", exBatchNoSmalls));//下列箱号库存不足，无法退料
                }

                mesDb.LineMaterialBills.Add(entity);
                mesDb.SaveChanges();
                entity.BillNo = DateTime.Today.ToString("yyyyMMdd") + (entity.PkId % 100000).ToString("00000");
                items.ForEach(_ =>
                {
                    _.BillNo = entity.BillNo;
                });
                mesDb.LineMaterialBillItems.AddRange(items);
                mesDb.SaveChanges();
            }
        }

        /// <summary>
        /// 查询物料单
        /// </summary>
        public Tuple<int, List<VLineMaterialBill>> QueryBills(int page, int limit, List<string> workshopCodes, int lineId, string workOrderNo, LineMaterialBillType? billType)
        {
            if (!workshopCodes.Any())
            {
                return new Tuple<int, List<VLineMaterialBill>>(0, new List<VLineMaterialBill>());
            }
            var query = mesDb.LineMaterialBills.AsNoTracking().Where(_ => _.Valid && workshopCodes.Contains(_.WorkshopCode));
            if (lineId > 0)
            {
                query = query.Where(_ => _.LineId == lineId);
            }
            if (!string.IsNullOrWhiteSpace(workOrderNo))
            {
                query = query.Where(_ => _.WorkOrderNo == workOrderNo);
            }
            if (billType.HasValue)
            {
                query = query.Where(_ => _.BillType == billType.Value);
            }
            var total = query.Count();
            query = query.OrderByDescending(_ => _.PkId);
            var skip = (page - 1) * limit;
            var entities = query.Skip(skip).Take(limit).ToList();
            var models = Mapper.Map<List<VLineMaterialBill>>(entities);

            var userIds = models.Select(_ => _.CreateBy).Distinct().ToList();
            var users = new UserMgr().QueryUsers(userIds);
            models.ForEach(model =>
            {
                model.CNCreateBy = users.FirstOrDefault(_ => _.PkId == model.CreateBy)?.TrueName;
            });
            return new Tuple<int, List<VLineMaterialBill>>(total, models);
        }

        /// <summary>
        /// 获取单据对象
        /// </summary>
        public VLineMaterialBill GetBill(string billNo)
        {
            var entity = mesDb.LineMaterialBills.AsNoTracking().FirstOrDefault(_ => _.BillNo == billNo && _.Valid);
            var model = Mapper.Map<VLineMaterialBill>(entity);
            if (model != null)
            {
                var items = mesDb.LineMaterialBillItems.AsNoTracking().Where(_ => _.BillNo == billNo && _.Valid).ToList();
                model.Items = Mapper.Map<List<VLineMaterialBillItem>>(items);
            }
            return model;
        }

        /// <summary>
        /// 查询剩余库存
        /// </summary>
        public Tuple<int, List<VLineStorage>> QueryLineStoragess(int page, int limit, string workshopCode, int lineId, string workOrderNo,
            bool? hasStorage, string billNo)
        {
            var query = mesDb.LineStorages.AsNoTracking().Where(_ => _.WorkshopCode == workshopCode && _.Valid);
            if (!string.IsNullOrWhiteSpace(billNo))
            {
                query = query.Where(_ => _.BillNo == billNo);
            }
            else
            {
                if (lineId > 0)
                {
                    query = query.Where(_ => _.LineId == lineId);
                }
                if (!string.IsNullOrWhiteSpace(workOrderNo))
                {
                    query = query.Where(_ => _.WorkOrderNo == workOrderNo);
                }
                if (hasStorage == true)
                {
                    query = query.Where(_ => _.Quantity > 0);
                }
                else if (hasStorage == false)
                {
                    query = query.Where(_ => _.Quantity == 0);
                }
            }
            var total = query.Count();
            query = query.OrderByDescending(_ => _.PkId);
            var skip = (page - 1) * limit;
            var entities = query.Skip(skip).Take(limit).ToList();
            return new Tuple<int, List<VLineStorage>>(total, Mapper.Map<List<VLineStorage>>(entities));
        }
    }
}
